/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ssp.service;

import java.util.ArrayList;
import java.util.List;
import ssp.database.DatabaseManager;
import ssp.database.ServiceMap;
import ssp.topology.Node;
import ssp.utility.Pair;

/**
 * フロントエンドサーバを表すクラス
 * @author yamazaki
 */
public class FrontendServer implements Node {
    
    /**
     * サーバID
     */
    private final int ID;
    
    /**
     * サーバ容量
     */
    private final double capacity;
    
    /**
     * ServiceEntryのリスト
     */
    private List<ServiceEntry> serviceEntryList;
    
    /**
     * リクエスト管理
     */
    private final RequestManager requestManager;
    
    /**
     * 自身が属しているネットワークコンポーネント
     */
    private Node connectedNWcomponent;
    
    /**
     * コンストラクタ
     * @param ID サーバID
     * @param capacity サーバ性能 
     */
    public FrontendServer(int ID, double capacity) {
        this.ID = ID;
        this.capacity = capacity;
        this.serviceEntryList = new ArrayList<ServiceEntry>();
        this.requestManager = new RequestManager(capacity);
    }

    /** 
     * @return the ID
     */
    public int getID() {
        return ID;
    }

    /**
     * @return the capacity
     */
    public double getCapacity() {
        return capacity;
    }
    
    /**
     * 指定のtypeIDに対応するServiceEntryを返す
     * @param ID ServiceEntryのtypeID
     * @return ServiceEntry
     */
    public ServiceEntry getServiceEntry(int ID) {
        for(ServiceEntry entry : serviceEntryList) {
            if(entry.getTypeID() == ID) {
                return entry;
            }
        }
        throw new IllegalArgumentException();
    }
    
    /**
     * @return the serviceEntryList
     */
    public List<ServiceEntry> getServiceEntry() {
        return new ArrayList<ServiceEntry>(this.serviceEntryList);
    }

    @Override
    public void addNeighbor(Node neighbor) {
        this.connectedNWcomponent = neighbor;
    }

    @Override
    public boolean isNeighbor(Node other) {
        return this.connectedNWcomponent.equals(other);
    }
    
    @Override
    public void removeNeighbor(Node nighbor) {
        this.connectedNWcomponent = null;
    }
    
    /**
     * 自身が属しているネットワークコンポーネントを返す
     * @return 自身が属しているネットワークコンポーネント
     */
    public Node getConnectedNWcomponent() {
        return this.connectedNWcomponent;
    }
   
    /**
     * 指定のtypeIDのServiceEntryのリストを返す
     * @param typeID
     * @return ServiceEntryのリスト
     */
    public List<ServiceEntry> searchServiceEntry(int typeID) {
        List<ServiceEntry> candidateList = new ArrayList<ServiceEntry>();
        for(ServiceEntry entry : this.serviceEntryList) {
            if(entry.getTypeID() == typeID) {
                candidateList.add(entry);
            }
        }
        return candidateList;
    }
    
    /**
     * 指定のServiceEntryへのリクエストの到着
     * @param entry ServiceEntry
     */
    public void arrival(ServiceEntry entry) {
        this.requestManager.start(entry);
    }
    
    /**
     * 指定のServiceEntryへのリクエストの離脱
     * @param entry ServiceEntry
     */
    public void departure(ServiceEntry entry) {
        this.requestManager.finish(entry);
    }
    
    /**
     * 指定のServiceEntryをリストに追加する
     * @param entry ServiceEntry
     */
    public void addServiceEntry(ServiceEntry entry) {
        this.serviceEntryList.add(entry);
    }
    
    /**
     * 指定のServiceEntryをリストから除外する
     * @param entry ServiceEntry
     */
    public void removeServiceEntry(ServiceEntry entry) {
        this.serviceEntryList.remove(entry);
    }
    
    /**
     * 指定のサービスを提供しているか否かを返す
     * @param entry ServiceEntry
     * @return 提供している場合はtrue
     */
    public boolean isProvideService(ServiceEntry entry) {
        return this.serviceEntryList.contains(entry);
    }
    
    /**
     * サービスマップを更新する
     * @param entry ServiceEntry
     * @param currentTime 更新時刻
     */
    public void updateServiceMap(ServiceEntry entry, double currentTime) {
        Pair<Integer, Integer> key = new Pair<Integer, Integer>(getID(), entry.getTypeID());
        ServiceMap DB = DatabaseManager.getINSTANCE().getServiceMap();
        DB.updateWorkloadTable(currentTime, key, entry.getWorkload());
        DB.updateChargeTable(currentTime, key, entry.getCharge());
        DB.updateQoSimdexListTable(currentTime, key, new ArrayList<Integer>(entry.getQoSindexList()));
        DB.updateAvailabilityTable(currentTime, ID, requestManager.getAvailability());
    }
    
}
